#include "ThreadPool.hpp"
#include <arpa/inet.h>
#include <cstring>
#include <unistd.h>

using func_t =std::function<std::string(const std::string&)>;

class TcpServer
{
private:
    ThreadPool *_pool;
    int _port;
    int _listensock;
    func_t _func;
    bool running;
private:
    void Service(int clisock)
    {
        char buffer[1024]={0};
        while(true)
        {
            memset(buffer, 0, sizeof(buffer));
            ssize_t bytesRead = recv(clisock, buffer, sizeof(buffer) - 1, 0);
            if (bytesRead <= 0)
            {
                std::cout << "Client disconnected\n";
                break;
            }

            std::cout << "Received: " << buffer;
            buffer[bytesRead]=0;
            std::string response = _func(buffer);
            send(clisock, response.c_str(), response.size(), 0);
        }
        close(clisock);
    }
public:
    TcpServer(int port,size_t threadNums,func_t func)
        :_port(port)
        ,_pool(ThreadPool::GetInstance(threadNums))
        ,_listensock(-1)
        ,_func(func)
        ,running(true)
    {
    }
    void InitServer()
    {
        //创建套接字
        _listensock=socket(AF_INET,SOCK_STREAM,0);
        struct sockaddr_in servaddr;
        socklen_t len=sizeof(servaddr);
        memset(&servaddr,0,len);
        servaddr.sin_family=AF_INET;
        servaddr.sin_port=htons(_port);
        servaddr.sin_addr.s_addr=INADDR_ANY;
        if(bind(_listensock,(struct sockaddr*)&servaddr,len)<0)
        {
            perror("TCP bind failed");
            close(_listensock);
            exit(EXIT_FAILURE);
        }
        if(listen(_listensock,10)<0)
        {
            perror("TCP listen failed");
            close(_listensock);
            exit(EXIT_FAILURE);
        }
    }
    
    void Loop()
    {
        while(running)
        {
            struct sockaddr_in cliaddr;
            socklen_t len=sizeof(cliaddr);
            memset(&cliaddr,0,len);
            int sockfd=::accept(_listensock,(struct sockaddr*)&cliaddr,&len);
            // 将该获取到的普通套接字交给线程池
            _pool->enqueue([sockfd,this](){Service(sockfd);});
        }
    }

    void Stop() {
        running = false;
        close(_listensock);
    }
};